package fr.miage.course7.gps;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Iterator;

/**
 * Classe gérant la communication via le socket.
 * @author Jonathan LAMOTTE
 *
 */
public class Communication implements Runnable {

    /**
     * Buffer d'entrée.
     */
    private BufferedReader in;

    /**
     * Pointeur sur la classe Serveur.
     */
    private Serveur serveur;

    /**
     * Socket de communication.
     */
    private Socket socket;

    /**
     * Buffer de sortie.
     */
    private PrintWriter out;

    /**
     * Constructeur.
     * @param sock : socket de communication
     * @param serv : pointeur sur la classe serveur
     */
    public Communication(final Socket sock, final Serveur serv) {
        this.serveur = serv;
        this.socket = sock;

        try {
            in = new BufferedReader(
                          new InputStreamReader(socket.getInputStream())
                                   );
            out = new PrintWriter(socket.getOutputStream());

        } catch (IOException e) {
            System.err.println("Impossible de communiquer avec " + socket);
        }
    }

    /**
     * Surcharge de la fonction run().
     */
    public final void run() {

        String message = "";

        String init = "[INIT]";
        String update = "[UPDATE]";
        String transmission = "[TRANSMISSION]";

        //Ecoute d'un message du client
        try {
            message = in.readLine();
        } catch (IOException e) {
            System.err.println("Deconnection de " + socket);
            serveur.remove(this);
        }

        while (message != null) {
            try {
                System.out.println(socket + " " + message);

                if (message.equals(init)) {
                    initClient();
                } else if (message.equals(update)) {
                    updateClient();
                } else if (message.substring(0, transmission.length())
                                  .equals(transmission)) {
                    int id = Integer.parseInt(message.substring(
                                                  transmission.length()
                                                               )
                                              );
                    System.out.println("Envoi la derniere transmission " + id);
                    positionClient(id);
                }

                //Ecoute d'un message du client
                message = in.readLine();

            } catch (IOException e) {
                System.err.println("Deconnection de " + socket);
                serveur.remove(this);
                //Arret du thread
                message = null;
            }
        }
    }

    /**
     * Envoi au client la position du participant id.
     * @param id : identifiant du client
     */
    private void positionClient(final int id) {
        Iterator<Participant> iter = serveur.iteratorParticipants();
        Participant participant;

        Transmission transmission;
        String message = "";
        String extensions = "";
        String xmlPart = "";
        String gpx = "";

        System.out.println("Mise a jour automatique du client");

        gpx = "<?xml version=\"1.0\" encoding=\"UTF-8\" "
                + "standalone=\"no\" ?>"
                + "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" "
                + "creator=\"byHand\" version=\"1.1\" "
                + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
                + "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 "
                + "http://www.topografix.com/GPX/1/1/gpx.xsd\">";

        while (iter.hasNext()) {
            participant = iter.next();
            if (participant.getIdentifiant() == id) {
                xmlPart = "<participant id='" + participant.getIdentifiant()
                       + "'"
                       +  "  derniereEtape='" + participant.getDerniereEtape()
                       + "'"
                       +  " />";

                extensions = extensions.concat(xmlPart);

                transmission = participant.getDerniereTransmission();
                message = message.concat(transmission.toXML());
            }
        }

        gpx = gpx.concat("<extension><participants>");
        gpx = gpx.concat(extensions);
        gpx = gpx.concat("</participants></extension>");
        gpx = gpx.concat(message);
        gpx = gpx.concat("</gpx>");
        System.out.println(gpx);
        out.println(gpx);
        out.flush();
    }

    /**
     * Fonction de mise a jour du client.
     */
    public final void updateClient() {
        Iterator<Participant> iter = serveur.iteratorParticipants();
        Participant participant;

        Transmission transmission;
        String message = "";
        String extensions = "";
        String xmlPart = "";
        String gpx = "";

        System.out.println("Mise a jour automatique du client " + socket);

        gpx = "<?xml version=\"1.0\" encoding=\"UTF-8\" "
                + "standalone=\"no\" ?>"
                + "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" "
                + "creator=\"byHand\" version=\"1.1\" "
                + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
                + "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 "
                + "http://www.topografix.com/GPX/1/1/gpx.xsd\">";

        while (iter.hasNext()) {
            participant = iter.next();
            xmlPart = "<participant id='" + participant.getIdentifiant() + "'"
                   +  "  derniereEtape='" + participant.getDerniereEtape() + "'"
                   +  " />";

            extensions = extensions.concat(xmlPart);

            transmission = participant.getDerniereTransmission();
            message = message.concat(transmission.toXML());
        }

        gpx = gpx.concat("<extension><participants>");
        gpx = gpx.concat(extensions);
        gpx = gpx.concat("</participants></extension>");
        gpx = gpx.concat(message);
        gpx = gpx.concat("</gpx>");
        System.out.println(gpx);
        out.println(gpx);
        out.flush();

    }

    /**
     * Fonction d'initialisation du client.
     */
    private void initClient() {
        Iterator<Participant> iter = serveur.iteratorParticipants();
        Participant participant;

        Iterator<Transmission> iterT;
        String extensions = "";
        String message = "";

        System.out.println("Initialisation du client");

        extensions = "<?xml version=\"1.0\" encoding=\"UTF-8\" "
            + "standalone=\"no\" ?>"
            + "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" "
            + "creator=\"byHand\" version=\"1.1\" "
            + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
            + "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 "
            + "http://www.topografix.com/GPX/1/1/gpx.xsd\">"
            + "<extensions><participants>";

        while (iter.hasNext()) {
            participant = iter.next();
            extensions = extensions.concat(participant.toXML());

            iterT = participant.getTransmissions().iterator();
            while (iterT.hasNext()) {
                message = message.concat(iterT.next().toXML());
            }
        }
        extensions = extensions.concat("</participants>");
        extensions = extensions.concat(serveur.etapesToXML());
        extensions = extensions.concat(serveur.itineraireToXML());
        extensions = extensions.concat("</extensions>");
        message = extensions.concat(message.concat("</gpx>"));

        out.println(message);
        out.flush();
    }
}

